package com.uwlaser.service.impl;

import cn.hutool.core.lang.Dict;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.uwlaser.domain.*;
import com.uwlaser.service.*;
import com.uwlaser.service.dto.*;
import com.uwlaser.service.mapper.*;
import com.uwlaser.utils.DateUtil;
import com.uwlaser.utils.StringUtils;
import com.uwlaser.utils.enums.DictValueEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author zk-Qin
* @date 2022-05-11
*/
@Service
@AllArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
@Slf4j
public class ProductServiceImpl implements ProductService {

    //工单
    private final PlanWorkOrderMapper planWorkOrderMapper;

    //编码规则
    private final ProductCodingMapper productCodingMapper;

    //编码规则详情
    private final ProductCodingRuleMapper productCodingRuleMapper;

    //日期转换
    private final ProductCodingDateConvertMapper productCodingDateConvertMapper;

    //产品型号
    private final ProductModelMapper productModelMapper;

    //主表
    private final DataMainMapper dataMainMapper;

    //单件物料
    private final DataMaterialSingleService dataMaterialSingleService;

    //批次物料
    private final DataMaterialBatchService dataMaterialBatchService;

    //过程参数
    private final DataCourseParamService dataCourseParamService;

    //过站数据
    private final DataPassStationService dataPassStationService;

    //产品工艺路线
    private final DataProductPathService dataProductPathService;

    //工艺路线
    private final CraftPathMapper craftPathMapper;

    //工艺路线详情
    private final CraftPathDetailMapper craftPathDetailMapper;

    //工艺参数
    private final CraftParamMapper craftParamMapper;

    //制造Bom
    private final ProductBomMapper productBomMapper;

    //混线
    private final PlanMixedLineMapper planMixedLineMapper;

    //混线规则
    private final PlanMixedRuleMapper planMixedRuleMapper;

    //电芯档位
    private final DataCellCapacityService dataCellCapacityService;

    //工单序列号
    private final OrderSerialService orderSerialService;
    /**
     * 获取产品序列号
     * @param requestParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetProductSnResult getProductSn(RequestParam<GetProductSnParam> requestParam) {
        //请求参数
        GetProductSnParam param = requestParam.getParam();
        //返回数据
        GetProductSnResult result = new GetProductSnResult();

        //获取当前产品型号信息
        ProductModel productModel = getProductModel(param.getProductCode());
        requestParam.setProductModel(productModel);

        //获取当前工段正在生产的工单
        PlanWorkOrder currentWorkOrder = getCurrentWorkOrder(param.getProductCode(), requestParam.getFactorySection().getModelCode(), DictValueEnum.WORK_STATUS_BEGIN.getValue());
        requestParam.setPlanWorkOrder(currentWorkOrder);

        log.info("<<<<<<开始生成条码,工单号["+currentWorkOrder.getWorkOrderCode()+"]>>>>>>");

        //获取当前生产工单序列号
        OrderSerial orderSerialQuery=new OrderSerial();
        orderSerialQuery.setWorkOrderCode(requestParam.getPlanWorkOrder().getWorkOrderCode());
        orderSerialQuery.setProductCode(requestParam.getProductModel().getProductCode());
        OrderSerial localOrderSerial = orderSerialService.getOne(new QueryWrapper<>(orderSerialQuery));
        requestParam.setOrderSerial(localOrderSerial);

        //生成产品序列号
        String productSn = createProductSn(requestParam);
        requestParam.setProductSn(productSn);
        //增加此条码是否已经存在产品信息判断，如果存在不需要重复添加产品信息
        DataMain dataMainParam=new DataMain();
        dataMainParam.setProductSn(productSn);
        DataMain dataMain = dataMainMapper.selectOne(new QueryWrapper<>(dataMainParam));
        if(dataMain!=null){
            result.setProductSn(productSn);
            result.setProductType(productModel.getProductType());
            result.setProductName(productModel.getProductName());
            result.setProductCode(productModel.getProductCode());
            result.setMsg("MES显示上一条码未出站，请勿重复请求唯一码");
            log.info("<<<<<<结束生成条码-主表已存在条码["+productSn+"]>>>>>>");
            return result;
        }

        //添加主表信息
        addDataMain(requestParam);

        //初始化工艺路线
        addProductPath(requestParam);

        if(localOrderSerial!=null){
            //更新工单序列号数量，只有存在本地工单序列号记录的才需要更新
            updateWorkOrderSerial(localOrderSerial);
        }


        //更新工单数量
        updateWorkOrderQty(currentWorkOrder);
        log.info("<<<<<<结束生成条码-反馈条码["+productSn+"]>>>>>>");
        //更新混线规则
        updateMixedRule(requestParam);

        result.setProductSn(productSn);
        result.setProductType(productModel.getProductType());
        result.setProductName(productModel.getProductName());
        result.setProductCode(productModel.getProductCode());

        return result;
    }


    /**
     * 添加产品序列号
     * @param requestParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AddProductSnResult addProductSn(RequestParam<AddProductSnParam> requestParam) {
        //请求参数
        AddProductSnParam param = requestParam.getParam();
        //返回数据
        AddProductSnResult result = new AddProductSnResult();

        requestParam.setProductSn(param.getProductSn());

        //获取当前产品型号信息
        ProductModel productModel = getProductModel(param.getProductCode());
        requestParam.setProductModel(productModel);
        /**
         * 添加唯一码前新增档位校验
         * */
        //请求参数
        GetCapacityByProductSnParam gearParam=new GetCapacityByProductSnParam();
        gearParam.setProductSn(param.getProductSn());
        gearParam.setProductCode(param.getProductCode());
        CheckGearResult checkGearResult = dataCellCapacityService.checkGear(gearParam);
        //判断档位校验结果
        if(checkGearResult.getResult()==400){
            throw new RuntimeException(checkGearResult.getMsg());
        }
        //填充档位数据
        requestParam.setCheckGearResult(checkGearResult);

        //获取当前工段正在生产的工单
        PlanWorkOrder currentWorkOrder = getCurrentWorkOrder(param.getProductCode(), requestParam.getFactorySection().getModelCode(), DictValueEnum.WORK_STATUS_BEGIN.getValue());
        requestParam.setPlanWorkOrder(currentWorkOrder);

        //查询当前产品序列号是否存在
        DataMain dataMain = getDataMainByProductSn(requestParam);

        if(dataMain == null){
            //添加主表信息
            addDataMain(requestParam);

            //初始化工艺路线
            addProductPath(requestParam);

            //更新工单数量
            updateWorkOrderQty(currentWorkOrder);

            //更新混线规则
            updateMixedRule(requestParam);
        }else {
            //如果存在则说明是复投的电芯，需要更改其工单编号和订单编号
            dataMain.setWorkOrderCode(currentWorkOrder.getWorkOrderCode());
            dataMain.setOrderCode(currentWorkOrder.getOrderCode());
            dataMainMapper.updateById(dataMain);
        }

        result.setProductSn(param.getProductSn());
        result.setProductType(productModel.getProductType());
        result.setProductName(productModel.getProductName());
        result.setProductCode(productModel.getProductCode());

        return result;
    }

    /**
     * 获取临时产品型号
     * @param requestParam
     * @return
     */
    @Override
    public GetProductSnResult getTempProductSn(RequestParam<GetProductSnParam> requestParam) {
        //临时编码标识
        requestParam.setTempSign("1");
        //请求参数
        GetProductSnParam param = requestParam.getParam();
        //返回数据
        GetProductSnResult result = new GetProductSnResult();

        //获取当前产品型号信息
        ProductModel productModel = getProductModel(param.getProductCode());
        requestParam.setProductModel(productModel);

        //获取当前工段正在生产的工单
        PlanWorkOrder currentWorkOrder = getCurrentWorkOrder(param.getProductCode(), requestParam.getFactorySection().getModelCode(), DictValueEnum.WORK_STATUS_BEGIN.getValue());
        requestParam.setPlanWorkOrder(currentWorkOrder);

        //生成临时产品序列号
        String productSn = createTempProductSn(requestParam);
        requestParam.setProductSn(productSn);

        //添加主表信息
        addDataMain(requestParam);

        //初始化工艺路线
        addProductPath(requestParam);

        //更新工单数量
        //updateWorkOrderQty(currentWorkOrder);

        //更新混线规则
        //updateMixedRule(requestParam);

        result.setProductSn(productSn);
        result.setProductType(productModel.getProductType());
        result.setProductName(productModel.getProductName());
        result.setProductCode(productModel.getProductCode());

        return result;
    }


    /**
     * 添加产品序列号 -多个
     * @param requestParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AddProductSnBatchResult addProductSnBatch(RequestParam<AddProductSnBatchParam> requestParam) {
        //请求参数
        AddProductSnBatchParam param = requestParam.getParam();
        //返回对象
        AddProductSnBatchResult result = new AddProductSnBatchResult();

        //第一个
        boolean isOne = true;

        //判断重复
        HashSet<String> hashSet = new HashSet<>();

        List<String> productSns = param.getProductSns();

        for (String productSn : productSns) {
            try {
                //判断是否重复
                if(!hashSet.add(productSn)){
                    throw new RuntimeException("当前产品序列号【"+productSn+"】重复，添加失败！");
                }
                //组装当个添加的数据
                AddProductSnParam addProductSnParam = new AddProductSnParam();
                addProductSnParam.setProductCode(param.getProductCode());
                addProductSnParam.setProductSn(productSn);
                addProductSnParam.setDeviceCode(param.getDeviceCode());
                addProductSnParam.setOperator(param.getOperator());
                addProductSnParam.setTimestamp(param.getTimestamp());

                RequestParam<AddProductSnParam> param1 = new RequestParam();
                param1.setParam(addProductSnParam);
                param1.setDeviceMain(requestParam.getDeviceMain());
                param1.setFactoryLine(requestParam.getFactoryLine());
                param1.setFactorySection(requestParam.getFactorySection());
                param1.setFactoryStation(requestParam.getFactoryStation());
                param1.setCraftOperation(requestParam.getCraftOperation());
                param1.setOperator(param.getOperator());
                param1.setProductSn(productSn);

                AddProductSnResult addResult = addProductSn(param1);
                //添加成功的第一个作为返回数据
                if(isOne){
                    result.setProductCode(addResult.getProductCode());
                    result.setProductName(addResult.getProductName());
                    result.setProductType(addResult.getProductType());
                    isOne = false;
                }
                result.addProductSn(productSn,"添加成功", HttpStatus.OK.value());
            } catch (Exception e){
                result.addProductSn(productSn,"添加失败！:"+e.getMessage(),HttpStatus.BAD_REQUEST.value());
            }
        }
        return result;
    }

    /**
     * 替换临时编码
     * @param requestParam
     */
    @Override
    public void replaceTempProductSn(RequestParam<ReplaceTempProductSnParam> requestParam) {
        //请求参数
        ReplaceTempProductSnParam param = requestParam.getParam();
        //替换单件物料
        DataMaterialSingle updateSingle = new DataMaterialSingle();
        updateSingle.setProductSn(param.getProductSn());

        DataMaterialSingle updateSingleWrapper = new DataMaterialSingle();
        updateSingleWrapper.setProductSn(param.getTempProductSn());
        updateSingleWrapper.setLienCode(requestParam.getFactoryLine().getModelCode());
        updateSingleWrapper.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataMaterialSingleService.update(updateSingle,new QueryWrapper<>(updateSingleWrapper));

        //替换批次物料
        DataMaterialBatch updateBatch = new DataMaterialBatch();
        updateBatch.setProductSn(param.getProductSn());

        DataMaterialBatch updateBatchWrapper = new DataMaterialBatch();
        updateBatchWrapper.setProductSn(param.getTempProductSn());
        updateBatchWrapper.setLienCode(requestParam.getFactoryLine().getModelCode());
        updateBatchWrapper.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataMaterialBatchService.update(updateBatch,new QueryWrapper<>(updateBatchWrapper));

        //替换过程参数
        DataCourseParam updateParam = new DataCourseParam();
        updateParam.setProductSn(param.getProductSn());

        DataCourseParam updateParamWrapper = new DataCourseParam();
        updateParamWrapper.setProductSn(param.getTempProductSn());
        updateParamWrapper.setLienCode(requestParam.getFactoryLine().getModelCode());
        updateParamWrapper.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataCourseParamService.update(updateParam,new QueryWrapper<>(updateParamWrapper));

        //替换进出站记录
        DataPassStation updatePassStation = new DataPassStation();
        updatePassStation.setProductSn(param.getProductSn());

        DataPassStation updatePassStationWrapper = new DataPassStation();
        updatePassStationWrapper.setProductSn(param.getTempProductSn());
        updatePassStationWrapper.setLienCode(requestParam.getFactoryLine().getModelCode());
        updatePassStationWrapper.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataPassStationService.update(updatePassStation,new QueryWrapper<>(updatePassStationWrapper));

        //删除主表信息
        DataMain dataMain = new DataMain();
        dataMain.setProductSn(param.getTempProductSn());
        dataMain.setLienCode(requestParam.getFactoryLine().getModelCode());
        dataMain.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataMainMapper.delete(new QueryWrapper<>(dataMain));

        //删除工艺路线
        DataProductPath dataProductPath = new DataProductPath();
        dataProductPath.setProductSn(param.getTempProductSn());
        dataProductPath.setLienCode(requestParam.getFactoryLine().getModelCode());
        dataProductPath.setSectionCode(requestParam.getFactorySection().getModelCode());
        List<DataProductPath> list = dataProductPathService.list(new QueryWrapper<>(dataProductPath));
        if(list == null || list.size() == 0){
            return;
        }

        //根据临时产品工艺路线更新正式产品工艺路线
        List<DataProductPath> updateList = list.stream().filter(path -> !path.getResult().equals(DictValueEnum.RESULT_UN.getValue())).collect(Collectors.toList());
        if(updateList == null || updateList.size() == 0){
            return;
        }
        for (DataProductPath productPath : updateList) {
            //更新内容
            DataProductPath update = new DataProductPath();
            update.setResult(productPath.getResult());
            update.setRepairSign(productPath.getRepairSign());
            //更新条件
            DataProductPath wrapper = new DataProductPath();
            wrapper.setProductSn(param.getProductSn());
            wrapper.setLienCode(productPath.getLienCode());
            wrapper.setSectionCode(productPath.getSectionCode());
            wrapper.setStationCode(productPath.getStationCode());
            wrapper.setOperationCode(productPath.getOperationCode());
            dataProductPathService.update(update,new QueryWrapper<>(wrapper));
        }

        //清除临时产品工艺路线
        dataProductPathService.remove(new QueryWrapper<>(dataProductPath));
    }

    /**
     * 根据产品序列号获取主表信息
     * @param requestParam
     * @return
     */
    private DataMain getDataMainByProductSn(RequestParam requestParam) {
        DataMain dataMain = new DataMain();
        dataMain.setLienCode(requestParam.getFactoryLine().getModelCode());
        dataMain.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataMain.setProductCode(requestParam.getProductModel().getProductCode());
        dataMain.setProductType(requestParam.getProductModel().getProductType());
        dataMain.setProductSn(requestParam.getProductSn());
        return dataMainMapper.selectOne(new QueryWrapper<>(dataMain));
    }


    /**
     * 添加主表信息
     * @param requestParam
     */
    private void addDataMain(RequestParam requestParam) {

        //产品型号
        ProductModel productModel = requestParam.getProductModel();
        //工单
        PlanWorkOrder planWorkOrder = requestParam.getPlanWorkOrder();
        //工艺路线
        CraftPath craftPath = getCraftPath(productModel.getProductCode());
        requestParam.setCraftPath(craftPath);
        //工艺参数
        CraftParam craftParam = getCraftParam(productModel.getProductCode());
        //制造Bom
        ProductBom productBom = getProductBom(productModel.getProductCode());
        //班次
        FactoryShift factoryShift = requestParam.getFactoryShift();


        DataMain dataMain = new DataMain();
        dataMain.setProductSn(requestParam.getProductSn());
        dataMain.setProductType(productModel.getProductType());
        dataMain.setProductCode(productModel.getProductCode());
        dataMain.setOrderCode(planWorkOrder.getOrderCode());
        dataMain.setWorkOrderCode(planWorkOrder.getWorkOrderCode());
        dataMain.setResult(DictValueEnum.RESULT_UN.getValue());//默认：未完成状态
        dataMain.setLienCode(requestParam.getFactoryLine().getModelCode());
        dataMain.setSectionCode(requestParam.getFactorySection().getModelCode());
        dataMain.setStartTime(new Date());
        dataMain.setPathCode(craftPath.getPathCode());
        dataMain.setPathVersion(craftPath.getVersion());
        dataMain.setParamsCode(craftParam.getParamsCode());
        dataMain.setParamsVersion(craftParam.getVersion());
        dataMain.setShiftCode(factoryShift.getShiftCode());
        dataMain.setTeamGroupId(factoryShift.getTeamGroupId());
        if(requestParam.getCheckGearResult()!=null){
            //填充容量和档位到电芯产品总览中
            dataMain.setGear(requestParam.getCheckGearResult().getGear());
            dataMain.setCapacity(requestParam.getCheckGearResult().getCapacity());
        }
        if (productBom != null) {
            dataMain.setBomCode(productBom.getBomCode());
            dataMain.setBomVersion(productBom.getVersion());
        }
        dataMain.setCreateBy(requestParam.getOperator());
        if(StringUtils.isEmpty(requestParam.getTempSign())){
            dataMain.setUntitled1(DictValueEnum.NO.getValue());
        }else {
            dataMain.setUntitled1(requestParam.getTempSign());
        }
        dataMainMapper.insert(dataMain);
    }

    /**
     * 添加工艺路线信息
     * @param requestParam
     */
    private void addProductPath(RequestParam requestParam) {
        //工艺路线
        CraftPath craftPath = requestParam.getCraftPath();

        //获取工艺路线详细信息
        CraftPathDetail craftPathDetail = new CraftPathDetail();
        craftPathDetail.setPathId(craftPath.getId());
        QueryWrapper<CraftPathDetail> wrapper = new QueryWrapper<>(craftPathDetail).orderByAsc("execution_order");
        List<CraftPathDetail> pathList = craftPathDetailMapper.selectList(wrapper);
        if(pathList == null || pathList.size() == 0){
            throw new RuntimeException("当前产品型号【"+requestParam.getProductModel().getProductCode()+"】未配置工艺路线详情，请配置后再试！");
        }

        ArrayList<DataProductPath> addList = new ArrayList<>();

        for (CraftPathDetail pathDetail : pathList) {
            DataProductPath productPath = new DataProductPath();
            productPath.setProductSn(requestParam.getProductSn());
            productPath.setProductCode(requestParam.getProductModel().getProductCode());
            productPath.setProductType(requestParam.getProductModel().getProductType());
            productPath.setOperationCode(pathDetail.getOperationCode());
            productPath.setOperationName(pathDetail.getOperationName());
            productPath.setExecutionOrder(pathDetail.getExecutionOrder());
            productPath.setNextStationCode(pathDetail.getNextStationCode());
            productPath.setUpStationCode(pathDetail.getUpStationCode());
            productPath.setIsCheck(pathDetail.getIsCheck());
            productPath.setIsShield(pathDetail.getIsShield());
            productPath.setRepairSign(DictValueEnum.REPAIR_SIGN_NORMAL.getValue()); //默认正常模式
            productPath.setResult(DictValueEnum.RESULT_UN.getValue());//默认未完成
            productPath.setLienCode(requestParam.getFactoryLine().getModelCode());
            productPath.setSectionCode(requestParam.getFactorySection().getModelCode());
            productPath.setStationCode(requestParam.getFactoryStation().getModelCode());
            productPath.setCreateBy(requestParam.getOperator());
            addList.add(productPath);
        }
        dataProductPathService.saveBatch(addList);
    }


    /**
     * 创建产品序列号
     * @param requestParam
     * @return
     */
    private String createProductSn(RequestParam<GetProductSnParam> requestParam) {
        String productCode=requestParam.getParam().getProductCode();
        //获取编码规则详情
        List<ProductCodingRule> codingRules = getProductCodingRules(productCode);
        //根据编码规则生成码
        StringBuilder productSn = new StringBuilder();

        for (ProductCodingRule codingRule : codingRules) {

            String ruleType = codingRule.getRuleType();

            String ruleCode = "";

            if(DictValueEnum.RULE_TYPE_GD.getValue().equals(ruleType)){
                //固定
                ruleCode = codingRule.getRuleContent();
            } else if(DictValueEnum.RULE_TYPE_DATE.getValue().equals(ruleType)){
                //日期
                ruleCode = getDateTimeByRule(codingRule);
            } else if(DictValueEnum.RULE_TYPE_SQL.getValue().equals(ruleType)){
                //SQL
                ruleCode = getSqlByRule(codingRule);
            }else if(DictValueEnum.RULE_TYPE_NUM.getValue().equals(ruleType)){
                //序列号
                ruleCode = getAutoSnByRule(codingRule,requestParam);
            }else if(DictValueEnum.RULE_TYPE_OTHER.getValue().equals(ruleType)){
                //其他
                ruleCode = getOtherByRule(codingRule,requestParam);
            }else{
                ruleCode = codingRule.getRuleContent();
            }
            productSn.append(ruleCode);
        }

        return productSn.toString();
    }

    /**
     * 创建临时产品序列号
     * @param requestParam
     * @return
     */
    private String createTempProductSn(RequestParam<GetProductSnParam> requestParam) {
        String productCode=requestParam.getParam().getProductCode();
        //获取编码规则详情
        List<ProductCodingRule> codingRules =  getProductCodingRules(productCode);
        //根据编码规则生成码
        StringBuilder productSn = new StringBuilder();
        productSn.append("TEMP");


        for (ProductCodingRule codingRule : codingRules) {

            String ruleType = codingRule.getRuleType();

            String ruleCode = "";

            if(DictValueEnum.RULE_TYPE_GD.getValue().equals(ruleType)){
                //固定
                ruleCode = codingRule.getRuleContent();
            } else if(DictValueEnum.RULE_TYPE_DATE.getValue().equals(ruleType)){
                //日期
                ruleCode = getDateTimeByRule(codingRule);
            } else if(DictValueEnum.RULE_TYPE_SQL.getValue().equals(ruleType)){
                //SQL
                ruleCode = getSqlByRule(codingRule);
            }else if(DictValueEnum.RULE_TYPE_NUM.getValue().equals(ruleType)){
                //序列号
                ruleCode = getTempAutoSnByRule(codingRule);
            }else if(DictValueEnum.RULE_TYPE_OTHER.getValue().equals(ruleType)){
                //其他
                ruleCode = getOtherByRule(codingRule,requestParam);
            }else{
                ruleCode = codingRule.getRuleContent();
            }
            productSn.append(ruleCode);
        }

        return productSn.toString();
    }



    /**
     * 获取编码规则详情
     * @param productCode
     * @return
     */
    private List<ProductCodingRule> getProductCodingRules(String productCode) {
        //获取启用的编码规则
        ProductCoding productCoding = new ProductCoding();
        productCoding.setProductCode(productCode);
        productCoding.setIsDisable(DictValueEnum.START.getValue());
        ProductCoding coding = productCodingMapper.selectOne(new QueryWrapper<>(productCoding));
        if(coding == null){
            throw new RuntimeException("当前产品型号【"+productCode+"】未配置或者未启用有对应的编码规则，请配置正确的编码规则后再生产！");
        }

        ProductCodingRule productCodingRule = new ProductCodingRule();
        productCodingRule.setCodingId(coding.getId());
        QueryWrapper<ProductCodingRule> wrapper = new QueryWrapper<>(productCodingRule).orderByAsc("rule_sort");
        List<ProductCodingRule> codingRules = productCodingRuleMapper.selectList(wrapper);
        if(codingRules == null || codingRules.size() == 0){
            throw new RuntimeException("当前产品的编码规则【"+coding.getCodingCode()+"】未配置，请配置正确的编码规则后再生产！");
        }
        return codingRules;
    }


    /**
     * 获取Bom信息
     * @param productCode
     * @return
     */
    private ProductBom getProductBom(String productCode) {
        ProductBom productBom = new ProductBom();
        productBom.setProductCode(productCode);
        productBom.setIsDisable(DictValueEnum.START.getValue());
        ProductBom bom = productBomMapper.selectOne(new QueryWrapper<>(productBom));
//        if(bom == null){
//            throw new RuntimeException("当前产品型号【"+productCode+"】未配置或者未启用Bom！请配置后再试。");
//        }
        return bom;
    }

    /**
     * 获取工艺参数
     * @param productCode
     * @return
     */
    private CraftParam getCraftParam(String productCode) {
        CraftParam craftParam = new CraftParam();
        craftParam.setProductCode(productCode);
        craftParam.setIsDisable(DictValueEnum.START.getValue());
        CraftParam param = craftParamMapper.selectOne(new QueryWrapper<>(craftParam));
        if(param == null){
            throw new RuntimeException("当前产品型号【"+productCode+"】未配置或者未启用工艺参数列表！请配置后再试。");
        }
        return param;
    }

    /**
     * 获取工艺路线
     * @param productCode
     * @return
     */
    private CraftPath getCraftPath(String productCode) {
        CraftPath craftPath = new CraftPath();
        craftPath.setProductCode(productCode);
        craftPath.setIsDisable(DictValueEnum.START.getValue());
        CraftPath path = craftPathMapper.selectOne(new QueryWrapper<>(craftPath));
        if(path == null){
            throw new RuntimeException("当前产品型号【"+productCode+"】未配置或者未启用工艺路线！请配置后再试。");
        }
        return path;
    }

    /**
     * 获取当前产品型号
     * @param productCode
     * @return
     */
    private ProductModel getProductModel(String productCode) {
        ProductModel productModel = new ProductModel();
        productModel.setProductCode(productCode);
        ProductModel model = productModelMapper.selectOne(new QueryWrapper<>(productModel));
        if(model == null){
            throw new RuntimeException("当前产品型号【"+productCode+"】没有在MES系统中维护，请维护后再试！");
        }
        return model;
    }


    /**
     * 获取当前正在生产的工单
     * @param pcode
     * @param scode
     * @param status
     * @return
     */
    public PlanWorkOrder getCurrentWorkOrder(String pcode,String scode,String status){
        PlanWorkOrder planWorkOrder = new PlanWorkOrder();
        planWorkOrder.setProductCode(pcode);
        planWorkOrder.setSectionCode(scode);
        planWorkOrder.setOrderStatus(status);
        //根据条件获取工单
        PlanWorkOrder workOrder = planWorkOrderMapper.selectOne(new QueryWrapper<>(planWorkOrder));
        if(workOrder == null){
            throw new RuntimeException("当前工段【"+scode+"】没有生产【"+pcode+"】的工单！请下发工单后再试！");
        }
        //判断当前工单生产数量已达到
        if((workOrder.getFinishQty() + workOrder.getOnlineQty()) >= workOrder.getRequiredQty()){
            throw new RuntimeException("当前工单【"+workOrder.getWorkOrderCode()+"】已达到需求数量！请下发新的工单后再续生产！");
        }
        return workOrder;
    }



    /**
     * 更新工单数量
     * @param currentWorkOrder
     */
    private void updateWorkOrderQty(PlanWorkOrder currentWorkOrder) {
        PlanWorkOrder planWorkOrder = new PlanWorkOrder();
        planWorkOrder.setId(currentWorkOrder.getId());
        planWorkOrder.setTotalQty(currentWorkOrder.getTotalQty() + 1);
        planWorkOrder.setOnlineQty(currentWorkOrder.getOnlineQty() + 1);
        planWorkOrderMapper.updateById(planWorkOrder);
    }

    /**
     * 更新工单序列号数量
     * */
    private void updateWorkOrderSerial(OrderSerial orderSerial) {
        orderSerial.setFirstSerial(orderSerial.getLastSerial());
        orderSerial.setLastSerial(orderSerial.getLastSerial()+1);
        orderSerial.setTotalSerialCount(orderSerial.getTotalSerialCount()+1);
        orderSerialService.updateById(orderSerial);
        OrderSerial newOrderSerial = orderSerialService.getById(orderSerial.getId());
        log.info("----更新工单序列号数量,跳码序列号["+newOrderSerial.getStartSerial()+"]---------------------------------------------------------");
        log.info("----更新工单序列号数量,当前序列号["+newOrderSerial.getFirstSerial()+"]---------------------------------------------------------");
        log.info("----更新工单序列号数量,下个序列号["+newOrderSerial.getLastSerial()+"]---------------------------------------------------------");
        log.info("----更新工单序列号数量,工单总数量["+newOrderSerial.getTotalSerialCount()+"]---------------------------------------------------------");
    }
    /**
     * 更新混线规则
     * @param requestParam
     */
    private void updateMixedRule(RequestParam requestParam) {
        //获取当前工段启用的混线规则
        PlanMixedLine planMixedLine = new PlanMixedLine();
        planMixedLine.setLineCode(requestParam.getFactoryLine().getModelCode());
        planMixedLine.setSectionCode(requestParam.getFactorySection().getModelCode());
        planMixedLine.setIsDisable(DictValueEnum.START.getValue());
        PlanMixedLine mixedLine = planMixedLineMapper.selectOne(new QueryWrapper<>(planMixedLine));
        if(mixedLine == null){
            return ;
        }
        //获取混线规则明细
        PlanMixedRule planMixedRule = new PlanMixedRule();
        planMixedRule.setMixedLineId(mixedLine.getId());
        QueryWrapper<PlanMixedRule> wrapper = new QueryWrapper<>(planMixedRule).orderByAsc("priority_level");
        List<PlanMixedRule> mixedRules = planMixedRuleMapper.selectList(wrapper);
        if(mixedRules == null || mixedRules.size() == 0){
            return ;
        }
        //当前正再循环的
        PlanMixedRule currentMixedRule = null;
        //下一循环的
        PlanMixedRule nextMixedRule = null;

        for (int i = 0; i < mixedRules.size(); i++) {
            PlanMixedRule mixedRule = mixedRules.get(i);
            //获取当前的
            if(DictValueEnum.YES.getValue().equals(mixedRule.getInProcess())){
                currentMixedRule = mixedRule;
                //获取下一个
                if(i + 1 >= mixedRules.size()){
                    nextMixedRule = mixedRules.get(0);
                } else {
                    nextMixedRule = mixedRules.get(i + 1);
                }
            }
        }

        //如果混线规则没有
        if(currentMixedRule == null || nextMixedRule == null){
            return ;
        }
        //判断当前循环的产品和上传的产品不一致
        if(!currentMixedRule.getProductCode().equals(requestParam.getProductModel().getProductCode())){
            throw new RuntimeException("上传的产品编码【"+requestParam.getProductModel().getProductCode()+"】和MES混线规则设置的产品编码【"+currentMixedRule.getProductCode()+"】不一致！通过获取当前工单接口得到正确的产品编码");
        }

        PlanMixedRule current = new PlanMixedRule();
        current.setId(currentMixedRule.getId());
        current.setProcessQty(currentMixedRule.getProcessQty() + 1);

        //如果执行数量达到指定数量后跳到下一个产品循环
        if(current.getProcessQty() >= currentMixedRule.getCycleQty() ){
            //当前循环设置否
            current.setInProcess(DictValueEnum.NO.getValue());
            current.setProcessQty(0);

            //下一个循环设置是
            PlanMixedRule next = new PlanMixedRule();
            next.setId(nextMixedRule.getId());
            next.setInProcess(DictValueEnum.YES.getValue());
            planMixedRuleMapper.updateById(next);
        }
        planMixedRuleMapper.updateById(current);
    }

    /**
     * 序列号
     * @param codingRule
     * @return
     */
    private String getAutoSnByRule(ProductCodingRule codingRule,RequestParam<GetProductSnParam> requestParam) {
        String ruleJson = codingRule.getRuleJson();
        ProductCodingSeriesDto codingSeries = JSONObject.parseObject(ruleJson,ProductCodingSeriesDto.class);
        if (codingSeries == null) {
            return "";
        }
        //自增序列号
        Integer autoSN = codingSeries.getSeriesInit() == null ? 1 : codingSeries.getSeriesInit() + 1;

        Integer length = codingSeries.getSeriesLength();

        //循环规则
        if (codingSeries.getIsLoog().equals(DictValueEnum.YES.getValue())) {
            //上一次重置序列号时间
            Date upDate = new Date(codingSeries.getUpdateTime() == null ? new Date().getTime() : codingSeries.getUpdateTime());
            //当前时间
            String currTime;
            //上一次重重置时间
            String upTime;
            //转换格式
            String format = null;
            //y：年，m：月，d：日
            switch (codingSeries.getBasic()) {
                case "0":
                    format = "yyyy";
                    break;
                case "1":
                    format = "MM";
                    break;
                case "2":
                    format = "dd";
                    break;
                case "3": {
                    /*
                     * 获取当前型号的正在生产的工单
                     * */
                    format = "dd";
                    //查询产品表中当前工单、型号是否存在最新的PACK条码
                    DataMainQueryParam dataMainQueryParam=new DataMainQueryParam();
                    dataMainQueryParam.setProductCode(requestParam.getParam().getProductCode());
                    dataMainQueryParam.setWorkOrderCode(requestParam.getPlanWorkOrder().getWorkOrderCode());
                    DataMainDto dataMainDto = dataMainMapper.selectLatestDataMain(dataMainQueryParam);
                    if(dataMainDto!=null){
                        log.info("----工单号["+requestParam.getPlanWorkOrder().getWorkOrderCode()
                                +"]最新PACK码["+dataMainDto.getProductSn()+"]创建时间为："+dataMainDto.getCreateTime()
                                +"]---------------------------------");
                        //如果此工单存在PACK条码，那么就判断是否有模组装箱出站记录
                        DataPassStation dataPassStation=new DataPassStation();
                        dataPassStation.setProductSn(dataMainDto.getProductSn());
                        dataPassStation.setStationCode("OP210");
                        DataPassStation passStation = dataPassStationService.getPassStation(dataPassStation);
                        if(passStation==null||passStation.getResult()==null){
                            //当前条码
                            autoSN =requestParam.getOrderSerial().getFirstSerial();
                            log.info("----产品条码["+dataPassStation.getProductSn()+"]未出站模组装箱---------------------------------");
                            log.info("----生成当前序列号["+autoSN+"]---------------------------------");
                        }else {
                            //下个条码
                            autoSN=requestParam.getOrderSerial().getLastSerial();
                            log.info("----上个产品条码["+dataPassStation.getProductSn()+"]以出站模组装箱---------------------------------");
                            log.info("----生成下个序列号["+autoSN+"]---------------------------------");
                        }
                    }else {
                            //如果没有则说明是此工单的第一个PACK条码，取得是初始序列号0+1
                            autoSN=requestParam.getOrderSerial().getFirstSerial()+1;
                            log.info("----生成工单首个序列号["+autoSN+"]---------------------------------");
                    }
                    break;
                }
                default:
                    format = "dd";
                    break;
            }
            currTime = DateUtil.getCurrentDate(format);
            upTime = DateUtil.getDateFormat(upDate, format);
            //如果时间不一样重置序列号
            if (codingSeries.getUpdateTime() == null || !currTime.equals(upTime)) {
                //并且不是根据订单重置序列号
                if(!("3".equals(codingSeries.getBasic()))){
                    autoSN = 1; //重置起始序号：1
                    codingSeries.setUpdateTime(new Date().getTime());//重置时间
                }
            }

        }
        //补充 0
        String prefix = "";
        int n = length - (autoSN.toString().length());
        for (int i = 0; i < n; i++) {
            prefix += "0";
        }
        //更新规则
        codingSeries.setSeriesInit(autoSN);
        ProductCodingRule productCodingRule = new ProductCodingRule();
        productCodingRule.setId(codingRule.getId());
        productCodingRule.setRuleJson(JSONObject.toJSONString(codingSeries));
        productCodingRuleMapper.updateById(productCodingRule);
        return prefix + autoSN.toString();
    }

    /**
     * 临时序列号
     * @param codingRule
     * @return
     */
    private String getTempAutoSnByRule(ProductCodingRule codingRule) {
        String ruleJson = codingRule.getRuleJson();
        ProductCodingSeriesDto codingSeries = JSONObject.parseObject(ruleJson,ProductCodingSeriesDto.class);
        if (codingSeries == null) {
            return "";
        }
        //自增序列号
        Integer autoSN = codingSeries.getTempSeriesInit() == null ? 1 : codingSeries.getTempSeriesInit() + 1;
        //长度
        Integer length = codingSeries.getSeriesLength();

        //循环规则
        if (codingSeries.getIsLoog().equals(DictValueEnum.YES.getValue())) {
            //上一次重置序列号时间
            Date upDate = new Date(codingSeries.getTempUpdateTime() == null ? new Date().getTime() : codingSeries.getTempUpdateTime());
            //当前时间
            String currTime;
            //上一次重重置时间
            String upTime;
            //转换格式
            String format;
            //y：年，m：月，d：日
            switch (codingSeries.getBasic()) {
                case "0":
                    format = "yyyy";
                    break;
                case "1":
                    format = "MM";
                    break;
                case "2":
                    format = "dd";
                    break;
                default:
                    format = "dd";
                    break;
            }
            currTime = DateUtil.getCurrentDate(format);
            upTime = DateUtil.getDateFormat(upDate, format);
            //如果时间不一样重置序列号
            if (codingSeries.getTempUpdateTime() == null || !currTime.equals(upTime)) {
                autoSN = 1; //重置起始序号：1
                codingSeries.setTempUpdateTime(new Date().getTime());//重置时间
            }

        }
        //补充 0
        String prefix = "";
        int n = length - (autoSN.toString().length());
        for (int i = 0; i < n; i++) {
            prefix += "0";
        }
        //更新规则
        codingSeries.setTempSeriesInit(autoSN);
        ProductCodingRule productCodingRule = new ProductCodingRule();
        productCodingRule.setId(codingRule.getId());
        productCodingRule.setRuleJson(JSONObject.toJSONString(codingSeries));
        productCodingRuleMapper.updateById(productCodingRule);
        return prefix + autoSN.toString();
    }

    /**
     * SQL
     * @param codingRule
     * @return
     */
    private String getSqlByRule(ProductCodingRule codingRule) {

        return productCodingRuleMapper.getSqlByRule(codingRule.getRuleJson());
    }

    /**
     * 日期
     * @param codingRule
     * @return
     */
    private String getDateTimeByRule(ProductCodingRule codingRule) {

        String ruleJson = codingRule.getRuleJson();
        ProductCodingDateDto codingDate = JSONObject.parseObject(ruleJson, ProductCodingDateDto.class);
        if (codingDate == null) {
            return "";
        }
        String dateFormat = codingDate.getDateFormat();
        //判断是否开启替换
        if (codingDate.getIsConvert().equals(DictValueEnum.YES.getValue())) {
            //获取转换表
            List<ProductCodingDateConvert> converts = productCodingDateConvertMapper.selectList(null);
            //替换规则
            HashMap<String, String> formatMap = new HashMap<String, String>();
            formatMap.put("yy", "Y");
            formatMap.put("yyyy", "Y");
            formatMap.put("MM", "M");
            formatMap.put("dd", "D");
            formatMap.put("HH", "H");
            for (String key : formatMap.keySet()) {
                if (key.contains(dateFormat)) {
                    SimpleDateFormat sf = new SimpleDateFormat(dateFormat);
                    String date = sf.format(new Date());
                    String type = formatMap.get(key);
                    String code = convertDate(converts, date, type);
                    if (code == null) {
                        dateFormat = dateFormat.replaceAll(key, date);
                    } else {
                        dateFormat = dateFormat.replaceAll(key, code);
                    }
                }
            }
            return dateFormat;
        } else {
            //普通规则
            SimpleDateFormat format = new SimpleDateFormat(dateFormat);
            return format.format(new Date());
        }
    }

    /**
     * 其他自定义
     * @param codingRule
     * @return
     */
    private String getOtherByRule(ProductCodingRule codingRule,RequestParam<GetProductSnParam> requestParam) {
        //获取当前产品正在生产的工单号
        PlanWorkOrder currentWorkOrder = getCurrentWorkOrder(requestParam.getParam().getProductCode(), requestParam.getFactorySection().getModelCode(), DictValueEnum.WORK_STATUS_BEGIN.getValue());
        return currentWorkOrder.getOrderCode();
    }


    /**
     * 转换日期代码
     *
     * @param dateListAll 转换列表
     * @param dateValue   日期值
     * @param dateType    类型
     * @return
     */
    public String convertDate(List<ProductCodingDateConvert> dateListAll, String dateValue, String dateType) {
        for (ProductCodingDateConvert code : dateListAll) {
            if (code.getDateValue().equals(dateValue) && code.getDateType().equals(dateType)) {
                return code.getConvertValue();
            }
        }
        return null;
    }
}

